﻿using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;

namespace Dexter.Web.Mvc.Annotations {
	/// <summary>
	/// This class contains a the validation for properties matches.
	/// </summary>
	[AttributeUsage ( AttributeTargets.Class , AllowMultiple = true , Inherited = true )]
	public sealed class PropertiesMustMatchAttribute : ValidationAttribute {
		const string DEFAULT_ERROR_MESSAGE = "'{0}' and '{1}' do not match.";
		readonly object typeId = new object ( );

		/// <summary>
		/// Initializes a new instance of the <see cref="PropertiesMustMatchAttribute"/> class.
		/// </summary>
		/// <param name="originalProperty">The original property.</param>
		/// <param name="confirmProperty">The confirm property.</param>
		public PropertiesMustMatchAttribute ( string originalProperty , string confirmProperty )
			: base ( DEFAULT_ERROR_MESSAGE ) {
			OriginalProperty = originalProperty;
			ConfirmProperty = confirmProperty;
		}

		/// <summary>
		/// Return the name of the property used to match.
		/// </summary>
		/// <value>The confirm property.</value>
		public string ConfirmProperty { get; private set; }
		
		/// <summary>
		/// Return the name of the property to compare.
		/// </summary>
		/// <value>The original property.</value>
		public string OriginalProperty { get; private set; }

		/// <summary>
		/// When implemented in a derived class, gets a unique identifier for this <see cref="T:System.Attribute"/>.
		/// </summary>
		/// <value></value>
		/// <returns>An <see cref="T:System.Object"/> that is a unique identifier for the attribute.</returns>
		public override object TypeId {
			get { return typeId; }
		}

		/// <summary>
		/// Applies formatting to an error message, based on the data field where the error occurred.
		/// </summary>
		/// <param name="name">The name to include in the formatted message.</param>
		/// <returns>
		/// An instance of the formatted error message.
		/// </returns>
		public override string FormatErrorMessage ( string name ) {
			return String.Format ( CultureInfo.CurrentUICulture , ErrorMessageString ,
			                       OriginalProperty , ConfirmProperty );
		}

		/// <summary>
		/// Determines whether the specified value of the object is valid.
		/// </summary>
		/// <param name="value">The value of the object to validate.</param>
		/// <returns>
		/// true if the specified value is valid; otherwise, false.
		/// </returns>
		public override bool IsValid ( object value ) {
			PropertyDescriptorCollection properties = TypeDescriptor.GetProperties ( value );
			object originalValue = properties.Find ( OriginalProperty , true /* ignoreCase */ ).GetValue ( value );
			object confirmValue = properties.Find ( ConfirmProperty , true /* ignoreCase */ ).GetValue ( value );
			return Equals ( originalValue , confirmValue );
		}
	}
}